package org.NooLab.glue.net.sockets.udp;

  
 
import java.util.* ;

import org.NooLab.glue.components.DataConnector;
import org.NooLab.glue.components.DataReceiverIntf;
 
 
import org.NooLab.utilities.logging.PrintLog;

/*
see: http://stackoverflow.com/questions/2687238/java-multithreading-udp-socket-programming

class Server{
    private final ServerSocket serverSocket;
    private final ExecutorService pool;

    public Server(int port, int poolSize) throws IOException {
      serverSocket = new ServerSocket(port);
      pool = Executors.newFixedThreadPool(poolSize);
    }

    public void serve() {
      try {
        while(true) {
          pool.execute(new Handler(serverSocket.accept()));
        }
      } catch (IOException ex) {
        pool.shutdown();
      }
    }
  }

  class Handler implements Runnable {
    private final Socket socket;
    Handler(Socket socket) { this.socket = socket; }
    public void run() {
      // receive the datagram packets
    }
 }


*/
public class UdpDataReceiver extends 
                                     Observable 
						     implements
						             DataReceiverIntf {

	private static final long serialVersionUID = -159480114318885656L;
 
	UdpObjects udphandler;
	int inboundSocketState = 0;
	
	/** default value : 9100 */
	int listenPort = 9100; 
	int ctrlPort = 9101; // control data in XML format
	
	int connectionTimeOutValue = 3000;
	
	PrintLog out = new PrintLog(2,true);
	
	/**
	 * 
	 * TODO
	 * - flexible choice between different protocols: all derive from DataReceiverIntf
	 *   -> using a factory
	 * 
	 * tcp running over port 80 and a dedicated address requires
	 * - first line dispatching, indicator of type of sender in the message
	 * - 
	 * 
	 * 
	 * @param listenport
	 * @param ctrlport
	 * @param observer
	 * @param description
	 */
	public UdpDataReceiver( int listenport , int ctrlport, Observer observer, String description ) {
		 
			if (description==null){
				description="" ;
			}
			if ( (description!=null) && (( description.contains("source")) || (description.contains("regID-")))){ 
 				out.print(3,"-- defining DataReceiver() - port: "+listenport+", name: "+description+", observer:"+ observer.toString()); 
			}
		addObserver(observer) ;
		
		listenPort = listenport ;
		ctrlPort = ctrlport ;
		
		// defining the udp component and starting it, it runs in a separate thread
		// note, that we route the provided observer directly to the udphandler , the DataReceiver
		// does NOT observe by itself
		udphandler = new UdpObjects( listenport, observer, description );
		
		if (udphandler.recthread != null){
			udphandler.start( description );
		}else{
			listenPort = -3;
			deleteObservers();
		}
	 		 
	}
	
	
	public void setObserver( Observer observer ){
		
		this.deleteObservers() ;
		addObserver(observer) ;
	}
	
	/* (non-Javadoc)
	 * @see org.NooLab.glue.udp.DataReceiverIntf#testAssignedPort()
	 */
	
	public int testAssignedPort(){
		int resultCode = -1 ;
		UdpObjects udptest = null ;
		
		try{
			
			udptest = new UdpObjects( listenPort, null, "test of port "+listenPort );

			inboundSocketState = udptest.getInboundSocket() ;
			
												out.print(5, "testAssignedPort(port="+listenPort+") -> "+ inboundSocketState);
												
			if (inboundSocketState==-7){ // cannot be opened -> is already assigned
				resultCode = 0;
			}else{
				resultCode = inboundSocketState; // 9 == it has been successfully connected 
			}
			
		}catch(Exception e){
			resultCode = -3;
		}
		
		if (udptest!=null){
			udptest.close() ;
			udptest = null ;
		}
		
		return resultCode;
	}
	
	
	/* (non-Javadoc)
	 * @see org.NooLab.glue.udp.DataReceiverIntf#closePort()
	 */
	
	public void closePort(){
														out.print(4,"-- DataReceiver() - closing port "+listenPort+" ...  "); 
		if (udphandler!=null){
			udphandler.close();
		}
		deleteObservers() ;
		udphandler=null;
	}
	
  

	/*
	 *
	 */
	
	public int getListenPort() {
		return listenPort;
	}

 


	public int getInboundSocketState() {
		return inboundSocketState;
	}


	public int getConnectionTimeOutValue() {
		return connectionTimeOutValue;
	}


	public void setConnectionTimeOutValue(int timeOutValue) {
		this.connectionTimeOutValue = timeOutValue;
	}

 
	
}  
	
	 

	
 
 

